package org.openmore.opc.service.impl;

import com.alibaba.fastjson.JSON;
import org.apache.shiro.SecurityUtils;
import org.apache.shiro.mgt.RealmSecurityManager;
import org.apache.shiro.session.Session;
import org.apache.shiro.subject.Subject;
import org.openmore.common.CommonUtils;
import org.openmore.common.exception.OpenmoreException;
import org.openmore.opc.dao.UserMapper;
import org.openmore.opc.dto.*;
import org.openmore.opc.entity.User;
import org.openmore.opc.entity.enums.LoginType;
import org.openmore.opc.entity.enums.UserType;
import org.openmore.opc.framework.MyThreadLocalConfig;
import org.openmore.opc.service.LoginService;
import org.openmore.opc.service.UserService;
import org.openmore.opc.service.WechatMiniService;
import org.openmore.opc.shiro.IRealmClearCache;
import org.openmore.opc.shiro.OpenmoreToken;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.util.StringUtils;
import tk.mybatis.mapper.entity.Example;

@Service
public class LoginServiceImpl extends BaseServiceImpl implements LoginService {

    @Autowired
    private UserService userService;

    @Autowired
    private WechatMiniService wechatMiniService;

    @Autowired
    private UserMapper userMapper;

    /**app三方登陆*/
    @Override
    public UserProfileDto appThirdLogin(String tenantId, LoginType type, WxMpUser wxUserInfo){
        if(StringUtils.isEmpty(tenantId)){
            throw new OpenmoreException(400, "应用ID不能为空");
        }
        User user = userService.getByOpenid(type, wxUserInfo.getOpenId());
        //APP首次三方登陆需要在此处创建用户
        if (user == null) {
            //throw new OpenmoreException("openId非法");
            user = new User();
            if(type == LoginType.QQ){ //保存qq openID
                user.setQqOpenid(wxUserInfo.getOpenId());
            }else if(type == LoginType.WECHAT_OPEN){ //保存wechat openID
                user.setWechatOpenid(wxUserInfo.getOpenId());
                user.setWechatName(wxUserInfo.getNickname());
            }else if(type == LoginType.WECHAT_MINIAPP){ //保存小程序 openID
                user.setMiniAppOpenid(wxUserInfo.getOpenId());
            }
            user.setAvatarUrl(wxUserInfo.getHeadImgUrl());
            user.setGender(wxUserInfo.getSexDesc());
            if(!StringUtils.isEmpty(wxUserInfo.getCountry()) && ! StringUtils.isEmpty(wxUserInfo.getCity())){
                user.setLocation(wxUserInfo.getCountry() + wxUserInfo.getCity());
            }
            user.setNickname(wxUserInfo.getNickname());
            user.setWechatOpenid(wxUserInfo.getOpenId());
            user.setUserType(UserType.USER);
            beforeInsert(user);
            userService.insert(user);
        }
        //用户已经绑定手机号码则直接登录
        if(!StringUtils.isEmpty(user.getPhone())){
            OpenmoreToken token = new OpenmoreToken(tenantId, LoginType.WECHAT_OPEN, user.getWechatOpenid(), user.getId(), null);
            shiroLogin(token);
        }
        return this.uploadInfor(user);
    }

    /**小程序登录*/
    @Override
    public UserProfileDto miniAppLogin(String tenantId, WechatMiniApp wechat){
        logger.debug("miniAppLogin");
        if(StringUtils.isEmpty(tenantId)){
            throw new OpenmoreException(400, "应用ID不能为空");
        }
        String sessionKey = "";
        BaseResponse sessionResponse = wechatMiniService.getJscodeSessionInfo(tenantId, wechat.getCode());
        if(sessionResponse.getCode() != 200){
            throw new OpenmoreException(sessionResponse.getCode(), sessionResponse.getMsg());
        }
        WxMaJscode2SessionResult session = (WxMaJscode2SessionResult) sessionResponse.getData();
        //sessionKey = session.getSessionKey();
        String openId = session.getOpenid();
        //String openId = "oAlhp5KERMvTGlYEPGbT9ts7hEGA";

        // 用户信息校验
        /*if (!this.wxService.getUserService().checkUserInfo(sessionKey, wechat.getRawData(), wechat.getSignature())) {
            throw new OpenmoreException("登录信息过期，请重新登录");
        }*/
        // WxMaUserInfo userInfo = this.wxService.getUserService().getUserInfo(sessionKey, wechat.getEncryptedData(), wechat.getIv());
        RawData rawData = JSON.parseObject(wechat.getRawData(), RawData.class);

        //解析性别
        String gender= null;
        if(null!= rawData.getGender()){
            gender = rawData.getGender()==1?"男":"女";
        }

        Example example = new Example(User.class);
        Example.Criteria criteria = example.createCriteria().andEqualTo("deleted", false);
        if(!StringUtils.isEmpty(openId)){
            criteria.andEqualTo("miniAppOpenid", openId);
        }
        User user = userMapper.selectOneByExample(example);
        if (user == null) {
            user = new User();
            user.setAvatarUrl(rawData.getAvatarUrl());
            user.setGender(gender);
            user.setNickname(rawData.getNickName());
            user.setMiniAppOpenid(openId);
            beforeInsert(user);
            userService.insert(user);
        }
//      如果用户头像有更新
        if (!user.getAvatarUrl().equals(rawData.getAvatarUrl())
                || !user.getNickname().equals(rawData.getNickName())) {
            user.setAvatarUrl(rawData.getAvatarUrl());
            user.setNickname(rawData.getNickName());
            user.setGender(gender);
            beforeUpdate(user);
            userMapper.updateByExample(user, example);
        }
        //用户已经绑定手机号码则直接登录
        if(!org.apache.commons.lang3.StringUtils.isEmpty(user.getPhone())){
            OpenmoreToken token = new OpenmoreToken(tenantId, LoginType.WECHAT_MINIAPP, user.getMiniAppOpenid(), user.getId(), null);
            shiroLogin(token);
        }
        return uploadInfor(user);
    }

    /**
     * 执行shiro登录
     *
     * @param token
     */
    private void shiroLogin(OpenmoreToken token) {
        Subject subject = SecurityUtils.getSubject();
//      已经授权过的，重新登录，先退出
        if (subject.isAuthenticated()) {
            this.logout();
        }
//      未登录，执行登录
        if (!subject.isAuthenticated()) {
            subject.login(token);
            if (subject.isAuthenticated()) {
                User user = null;
//              shiro登录成功，没有找到员工，则尝试找用户表，分三种登录情况
                if (token.getType() == LoginType.PASSWORD) {//密码登录
                    user = userService.getUserByPhone(token.getTenantId(), CommonUtils.trimPhonePrefixCode(token.getUsername()));
                } else if (token.getType() == LoginType.WECHAT_OPEN || token.getType() == LoginType.QQ || token.getType() == LoginType.WEIBO) {//微信登录
                    user = userService.getByOpenid(token.getType(), token.getUsername());
                } else {
                    throw new OpenmoreException(4001, "非法登录！");
                }
            }
        }
    }

    /**shiro退出登录*/
    private void logout() {
        //执行登录操作
        insertLog("用户退出登录");
        Subject subject = SecurityUtils.getSubject();
        RealmSecurityManager securityManager = (RealmSecurityManager) SecurityUtils.getSecurityManager();
        IRealmClearCache realm = (IRealmClearCache) securityManager.getRealms().iterator().next();
        realm.clearCache();
        subject.logout();
    }

    public UserProfileDto uploadInfor(User user) {
        //判断用户
        User userDto = null;
        if (!StringUtils.isEmpty(user.getId())) {
            userDto = userService.getEntityById(user.getId());
            logger.debug("418: getUser: {}", userDto);
            if (null == userDto) {
                //如果已经不是用户，清除用户id
                user.setId(null);
                logger.error("==>wechat login but user is not exist wechatUserId:" + user.getId());
                throw new OpenmoreException(4001, "账户身份信息已更改，请联系管理员");
            } else {
                if (userDto.getLocked()) {
                    throw new OpenmoreException(4001, "您的账户已被锁定，请联系管理员");
                }
                //qq登录
                //accountService.shiroLogin(new OpenmoreToken(LoginType.WECHAT_OPEN, user.getOpenid(), null, null));
                //logger.debug("430: accountService.shiroLogin OK");
                userDto.setLastLoginIp(MyThreadLocalConfig.getIPAddr());
                userDto.setAvatarUrl(user.getAvatarUrl());
                //beforeUpdate(staff);
                //staffMapper.updateByExample(staff, staffExample);
                userService.update(userDto);
                return buildUserProfile(user);
            }
        }
        //微信登录
        // accountService.shiroLogin(new OpenmoreToken(LoginType.WECHAT_OPEN, user.getOpenid(), null, null));
        return buildUserProfile(user);
    }

    private UserProfileDto buildUserProfile(User user) {
        UserProfileDto profile = new UserProfileDto();
        profile.setId(user.getId());
//        profile.setWbOpenId(user.get);
        profile.setAvatarUrl(user.getAvatarUrl());
        profile.setCreatedTime(user.getCreatedTime());
        profile.setUpdatedTime(user.getUpdatedTime());
        profile.setLocation(user.getLocation());
        profile.setBirthday(user.getBirthday());
//        profile.setUsername(user.getNickname());
        profile.setGender(user.getGender());
        profile.setUsername(user.getNickname());
        profile.setType(user.getUserType());
        profile.setMiniAppOpenId(user.getMiniAppOpenid());
        profile.setWxOpenId(user.getWechatOpenid());
        profile.setQqOpenId(user.getQqOpenid());
        profile.setWechatName(user.getWechatName());
//        if (residentDto != null) {
//            profile.setId(residentDto.getId());
//            profile.setBirthday(residentDto.getBirthday());
//            profile.setGender(residentDto.getGender());
//            profile.setType("RESIDENT");
//            profile.setUsername(residentDto.getName());
//            profile.setFullAddress(residentDto.getFullAddress());
//            profile.setLocation(residentDto.getFullAddress());
//            profile.setIdno(CommonUtils.replaceIdNumber(residentDto.getIdno()));
//        }
        //insertLog("用户微信登录：" + token.getUsername());
        if(SecurityUtils.getSubject().isAuthenticated()){
            Session session = SecurityUtils.getSubject().getSession();
            profile.setToken((String) session.getId());
            profile.setPhone(CommonUtils.replacePhoneNumber(user.getPhone()));
        }else{
            profile.setPhone(user.getPhone());
        }
        return profile;
    }
}
